﻿// oil.cpp : 定义应用程序的入口点。

#include "pch.h"
#include "framework.h"
#include "oil.h"


#define NDEBUG
#define _CRT_SECURE_NO_WARNINGS
#include <assert.h>

using namespace std;

#define MAX_LOADSTRING 100
// 定义资源ID
#define IDB_BITMAP1 134


#ifdef _WIN32
#define PATH_DELIMITER "\\"
#else
#define PATH_DELIMITER "/"
#endif

#define MAX_PATH_LEN 256

#ifdef WIN32
#define ACCESS(fileName,accessMode) _access(fileName,accessMode)
#define MKDIR(path) _mkdir(path)
#else
#define ACCESS(fileName,accessMode) access(fileName,accessMode)
#define MKDIR(path) mkdir(path,S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)
#endif

// 全局变量:
HINSTANCE hInst;                                // 当前实例
WCHAR szTitle[MAX_LOADSTRING];                  // 标题栏文本
WCHAR szWindowClass[MAX_LOADSTRING];            // 主窗口类名

// 此代码模块中包含的函数的前向声明:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    SelctFile(HWND, UINT, WPARAM, LPARAM);

HWND hEdit;// 文本框窗口句柄
HWND hButton1;
HWND hButton2;
HWND hButton3;
HWND hButton4;
HWND hListBox;
HWND hProgressBar;
HWND hStatic;

//是否输出网格点集和拓扑信息
bool OutputsMeshInformation = false;
//网格数据bin文件地址
string binFilePath = "";
int iProgressBar = 0;

// 防抖时间间隔（例如，3000 毫秒）
const DWORD DEBOUNCE_INTERVAL = 3000;
// 上次点击的时间戳
DWORD lastClickTime = 0;



#include <intrin.h>
void getCpuInfo()
{
	int cpuInfo[4] = { -1 };
	char cpu_manufacture[32] = { 0 };
	char cpu_type[32] = { 0 };
	char cpu_freq[32] = { 0 };

	__cpuid(cpuInfo, 0x80000002);
	memcpy(cpu_manufacture, cpuInfo, sizeof(cpuInfo));

	__cpuid(cpuInfo, 0x80000003);
	memcpy(cpu_type, cpuInfo, sizeof(cpuInfo));

	__cpuid(cpuInfo, 0x80000004);
	memcpy(cpu_freq, cpuInfo, sizeof(cpuInfo));

	std::cout << "CPU manufacture: " << cpu_manufacture << std::endl;
	std::cout << "CPU type: " << cpu_type << std::endl;
	std::cout << "CPU main frequency: " << cpu_freq << std::endl;
}

int get_core_count() {
	int cpuinfo[4];
	__cpuid(cpuinfo, 1);
	// EBX[23:16] 是逻辑核心数
	int core_count = (cpuinfo[1] >> 16) & 0xFF;
	//std::cout << "Logical cores: " << core_count << std::endl;
	return core_count;
}

//std::condition_variable cv;
//std::mutex cv_m;
//bool done = false; // 全局标志，表示工作线程是否完成

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: 在此处放置代码。

    // 初始化全局字符串
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_OIL, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // 执行应用程序初始化:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

	// MFC初始化 在dll中使用MFC时由于afxCurrentResourceHandle=NULL
	// 会引起对话框在创建时调用AfxGetResourceHandle()方法断言失败，
	// 解决该问题需要在程序使用MFC类之前调用如下方法即可
	//AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0);
	if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
	{
		//_Module.LogEvent(_T("MFC初始化错误！"), EVENTLOG_ERROR_TYPE );
		return 1;
	}

    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_OIL));

    MSG msg;

    // 主消息循环:
    while (GetMessage(&msg, nullptr, 0, 0))
    {

		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}

		// 检查工作线程是否完成
		//std::unique_lock<std::mutex> lk(cv_m);
		//if (done) {
			//cv.wait(lk, [] { return done; });
			// 可以在这里决定是否退出消息循环
			// 如果要退出，可以调用 
			//PostQuitMessage(0);
		//}

		// 检查工作线程是否完成
		//std::unique_lock<std::mutex> lk(cv_m);
		//if (done) {
			//cv.wait(lk); // 等待工作线程设置完成标志
			//break; // 退出消息循环
		//}
		//使用互斥锁（mutexes）、条件变量（condition variables）、事件（events）
		//等同步机制来确保线程间的正确通信。

	}

    return (int) msg.wParam;
}

//
//  函数: MyRegisterClass()
//
//  目标: 注册窗口类。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_OIL));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_OIL);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));


    return RegisterClassExW(&wcex);
}

//
//   函数: InitInstance(HINSTANCE, int)
//
//   目标: 保存实例句柄并创建主窗口
//
//   注释:
//
//        在此函数中，我们在全局变量中保存实例句柄并
//        创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   hInst = hInstance; // 将实例句柄存储在全局变量中

   HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);


   if (!hWnd)
   {
       MessageBox(NULL,
           _T("Call to CreateWindow failed!"),
           _T("Windows Desktop Guided Tour"),
           NULL);

       return FALSE;
   }


   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

int DisplayConfirmSaveAsMessageBox(HWND hWnd)
{
    int msgboxID = MessageBox(
        NULL,
        L"即将退出软件，请注意保存文件!",
        L"退出",
        MB_ICONEXCLAMATION | MB_YESNO
    );

    if (msgboxID == IDYES)
    {
        // TODO: 销毁对话框
        DestroyWindow(hWnd);
    }

    return msgboxID;
}

#define MAX_CFileDialog_FILE_COUNT 99

#define FILE_LIST_BUFFER_SIZE ((MAX_CFileDialog_FILE_COUNT * (MAX_PATH + 1)) + 1)


//比较函数 降序为 a.first<b.first
//若是想排序的第二个数字，把first改成second即可
static bool cmp_key(const pair<int, long long> left, const pair<int, long long> right) {
	return left.first < right.first;
}

static bool cmp_value(const pair<int, long long> left, const pair<int, long long> right) {
	return left.second < right.second;
}

static map<int, long long>::const_iterator extremeValueAnalysis(map<int, long long> m, string extype = "value", string type = "min") {

	map<int, long long>::const_iterator extValue;

	if (extype == "key") {
		//比较map的key
		map<int, long long>::const_iterator it;
		if (type == "min") {
			it = m.begin();//相当于获取了平衡树最左下面（most left）的结点的迭代器   
			it++;
			//cout << "min " << it->first << " " << it->second << endl;//最小的key值 
			extValue = it;
		}
		else if (type == "max") {
			it = m.end();//相当于获取了平衡树最右下面（most right）的结点的迭代器   
			it--;
			//cout << "max " << it->first << " " << it->second << endl; //最大的key值
			extValue = it;
		}
	}
	else if(extype =="value") {
		//比较map的value

		if (type == "max") {
			//迭代器 返回值为 key : value
			auto imax = max_element(m.begin(), m.end(), cmp_value);
			//cout << imax->first << "_" << imax->second << endl;
			extValue = imax;
		}
		else if (type == "min") {
			//i是迭代器 返回值为19-20
			auto imin = min_element(m.begin(), m.end(), cmp_value);
			//cout << imin->first << "_" << imin->second << endl;
			extValue = imin;
		}

	}
	
	return extValue;

}


// 假设这是你的对话框中的某个函数
static void OnOpenBinFile(HWND hWnd)
{
	//CFileDialog dlgFile(TRUE, _T("bin"), NULL, OFN_ALLOWMULTISELECT | OFN_EXPLORER, NULL);
	CFileDialog dlgFile(TRUE,
		_T("bin"),
		_T(""),
		OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST,
		_T("Binary Files (*.bin)|*.bin|All Files (*.*)|*.*||"),
		//_T("Text Files (*.txt)|*.txt|All Files (*.*)|*.*||"),
		NULL);

	//OPENFILENAME& ofn = dlgFile.GetOFN();
	//TCHAR szFile[MAX_PATH] = { 0 }; // 保存获取文件名称的缓冲区
	//ofn.lStructSize = sizeof(OPENFILENAME);
	//ofn.hwndOwner = NULL;
	//ofn.lpstrFile = szFile;

	//ofn.Flags |= OFN_ALLOWMULTISELECT;
	//ofn.lpstrFilter = L"Binary Files(*.bin) | *.bin | All Files(*.*) | *.* || ";
	//ofn.nFilterIndex = 1;
	if (IDOK == dlgFile.DoModal()) {

		/*
		CStringArray strArrFilePaths;
		POSITION pos = dlgFile.GetStartPosition();
		while (pos != NULL)
			strArrFilePaths.Add(dlgFile.GetNextPathName(pos));


		for (int size = 0; size < strArrFilePaths.GetSize(); size++)
		{
			auto result = ShellExecute(NULL, L"open", strArrFilePaths[size], NULL, NULL, SW_SHOWNORMAL);
		}
		*/
		// 这里可以添加代码来处理选中的文件
		CString strFilePath = L"";
		strFilePath = dlgFile.GetPathName();

		//wchar_t* p = strFilePath.GetBuffer(FILE_LIST_BUFFER_SIZE);

		SetDlgItemTextW(hWnd, IDC_EDIT1, strFilePath);
	}
	
	/*
	// 创建一个文件打开对话框，仅显示 .bin 文件
	CFileDialog* pFileDlg = new CFileDialog(TRUE,
        _T("bin"), 
        _T(""),
        OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST,
		_T("Binary Files (*.bin)|*.bin|All Files (*.*)|*.*||"),
		//_T("Text Files (*.txt)|*.txt|All Files (*.*)|*.*||"),
		NULL);
	
	INT_PTR result = pFileDlg->DoModal();
	if (result == IDOK)
	{

		// 这里可以添加代码来处理选中的文件
		CString strFilePath = L"";
		strFilePath = pFileDlg->GetPathName();

		SetDlgItemTextW(hWnd, IDC_EDIT1, strFilePath);

	}
	else if (result == IDCANCEL)
	{
		// 使用 pFileDlg
	    delete pFileDlg; // 当不再需要时销毁对象
		return 1;
	}
	
	// 使用 pFileDlg
	delete pFileDlg; // 当不再需要时销毁对象
	
	return 0;
	*/
}

static void OnBnClickedSaveButton(HWND hWnd)
{
	// TODO: Add your control notification handler code here   
	// 设置过滤器   
	TCHAR szFilter[] = _T("文本文件(*.txt)|*.txt|Word文件(*.doc)|*.doc|所有文件(*.*)|*.*||");
	// 构造保存文件对话框   
	CFileDialog fileDlg(FALSE, _T("txt"), _T("test"), OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, szFilter);
	CString strFilePath;

	// 显示保存文件对话框   
	if (IDOK == fileDlg.DoModal())
	{
		// 如果点击了文件对话框上的“保存”按钮，则将选择的文件路径显示到编辑框里   
		strFilePath = fileDlg.GetPathName();
		SetDlgItemText( hWnd,IDC_SAVE_EDIT, strFilePath);
	}
}

static void setEditText(HWND m_hwndEdit, LPCTSTR lpszText)
{
	SetWindowText(m_hwndEdit, lpszText);
}

static CString getEditText(HWND m_hwndEdit)
{
	CString strText;
	GetWindowText(m_hwndEdit, strText.GetBuffer(256), 256);
	strText.ReleaseBuffer();
	return strText;
}

static string WChar2Ansi(LPCWSTR pwszSrc)
{
	int nLen = WideCharToMultiByte(CP_ACP, 0, pwszSrc, -1, NULL, 0, NULL, NULL);
	if (nLen <= 0) return std::string("");
	char* pszDst = new char[nLen];
	if (NULL == pszDst) return std::string("");
	WideCharToMultiByte(CP_ACP, 0, pwszSrc, -1, pszDst, nLen, NULL, NULL);
	pszDst[nLen - 1] = 0;
	std::string strTemp(pszDst);
	delete[] pszDst;
	return strTemp;
}

static string cstToStr(CString strFilePath) {
	string str = "";
	// len = strFilePath.GetLength();
	//std::string str(len, 0); // 预分配空间

	//for (int i = 0; i < len; ++i) {
	//	str[i] = (char)strFilePath.GetAt(i);
	//}

	if (!strFilePath.IsEmpty())
	{
		/*
		char* ansiStr = CW2A(strFilePath.GetString());

		if (ansiStr) {
			str = ansiStr;
		}
		*/

		//str = CW2A(strFilePath.GetString());

		//str = CT2A(strFilePath);

		/*
		// 使用 GetBuffer 方法获取 LPCTSTR
		LPCTSTR lpStr = strFilePath.GetBuffer(strFilePath.GetLength());

		std::wstring wstr(lpStr);

		// 然后将 std::wstring 转换为 std::string
		str.assign(wstr.begin(), wstr.end()); // 这不会进行编码转换

		// 如果你需要从 UTF-16 或 UTF-32 转换到 UTF-8，你需要使用编码转换
		std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;
		str = converter.to_bytes(wstr);

		// 释放缓冲区（如果使用了 GetBuffer）
		strFilePath.ReleaseBuffer();
		*/

		//std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;
		//str = converter.to_bytes((LPCTSTR)strFilePath);

		//CString to string, 要看你的CString用的是UNICODE还是非UNICODE,
		//非UNICODE就简单了
		//str = (strFilePath.GetBuffer(strFilePath.GetLength()));
		//GetBuffer()后一定要ReleaseBuffer(), 否则就没有释放缓冲区所占的空间.

		//UNICODE就麻烦点 需要转换函数
		//string WChar2Ansi(LPCWSTR pwszSrc){}

		str = WChar2Ansi(strFilePath.GetBuffer(strFilePath.GetLength()));
		strFilePath.ReleaseBuffer();

	}
	else
	{
		// 处理空字符串的情况
	}

	

	std::string toReplace = "\\";
	std::string replacement = "\\\\";

	size_t pos = 0;
	while ((pos = str.find(toReplace, pos)) != std::string::npos) {
		str.replace(pos, toReplace.length(), replacement);
		pos += replacement.length(); // 移动到替换字符串之后的位置
	}

	
	return str;
}

// 在某个地方添加字符串到列表框
void AddItemToListBox(HWND hwndListBox, LPCTSTR pszItem)
{
	SendMessage(hwndListBox, LB_ADDSTRING, 0, (LPARAM)pszItem);
}

void FindCsvFile()
{
	char data_path[MAX_PATH];       //获取数据所在的目录
	//获取项目所在目录 
	GetCurrentDirectoryA(MAX_PATH, data_path);
	strcat_s(data_path, "\\15\\*.csv");   //拼接字符串

	CFileFind filefind;

	BOOL bFound;
	bFound = filefind.FindFile(CString(data_path));
	CString strtemp;
	while (bFound)
	{
		bFound = filefind.FindNextFile();
		if (filefind.IsDirectory() || filefind.IsDots())
		{
			continue;
		}
		else {
			strtemp = filefind.GetFilePath();
			//hListBox.AddString(CString(strtemp)); //为listBox控件添加数据
		}
	}
}

// 读取bin文件
long long getBinSize(string path)
{
	long long size = 0;
	ifstream infile(path, ifstream::binary);

	infile.seekg(0, infile.end);
	size = infile.tellg();
	infile.seekg(0, infile.beg);

	infile.close();
	return size;
}

//网格三维坐标结构体
struct Point {
	Point() {};
	double x = 0, y = 0, z = 0;
	Point(double x, double y, double z) : x(x), y(y), z(z) {}
};

//网格三维拓扑面结构体
struct Face {
	Face() {};
	long long p1 = 0, p2 = 0, p3 = 0, p4 = 0;
	Face(long long p1, long long p2, long long p3, long long p4) : p1(p1), p2(p2), p3(p3), p4(p4) {}
};

// 类型long转换为string
string longToString(long long num) {
	stringstream ss1;
	ss1 << num;  // or any other type
	string result = ss1.str();   // use .str() to get a string back
	return result;
}

// 使用字符分割
void strSplit(const string& str, const char split, vector<string>& res)
{
	if (str == "")		return;
	//在字符串末尾也加入分隔符，方便截取最后一段
	string strs = str + split;
	size_t pos = strs.find(split);

	// 若找不到内容则字符串搜索函数返回 npos
	while (pos != strs.npos)
	{
		string temp = strs.substr(0, pos);
		res.push_back(temp);
		//去掉已分割的字符串,在剩下的字符串中进行分割
		strs = strs.substr(pos + 1, strs.size());
		pos = strs.find(split);
	}
}
// 使用字符串分割
void strSplit(const string& str, const string& splits, vector<string>& res)
{
	if (str == "")		return;
	//在字符串末尾也加入分隔符，方便截取最后一段
	string strs = str + splits;
	size_t pos = strs.find(splits);
	int step = splits.size();

	// 若找不到内容则字符串搜索函数返回 npos
	while (pos != strs.npos)
	{
		string temp = strs.substr(0, pos);
		res.push_back(temp);
		//去掉已分割的字符串,在剩下的字符串中进行分割
		strs = strs.substr(pos + step, strs.size());
		pos = strs.find(splits);
	}
}

// 三维向量类
class Vector3D {
public:
	double x, y, z;

	Vector3D(double x = 0.0, double y = 0.0, double z = 0.0) : x(x), y(y), z(z) {}

	// 向量减法
	Vector3D operator-(const Vector3D& v) const {
		return Vector3D(x - v.x, y - v.y, z - v.z);
	}

	// 向量叉乘
	Vector3D cross(const Vector3D& v) const {
		return Vector3D(
			y * v.z - z * v.y,
			z * v.x - x * v.z,
			x * v.y - y * v.x
		);
	}

	// 向量点积
	double dot(const Vector3D& v) const {
		return x * v.x + y * v.y + z * v.z;
	}
};

// 计算六面体体积类
class Hexahedron {
private:
	vector<Vector3D> vertices;  // 8个顶点

public:
	Hexahedron(const vector<Vector3D>& verts) : vertices(verts) {
		if (vertices.size() != 8) {
			throw invalid_argument("Hexahedron must have exactly 8 vertices.");
		}
	}
	~Hexahedron() {
		vector<Vector3D>().swap(vertices);
		//vertices.clear();
	}

	// 计算体积
	double getVolume() const {
		// 选择一个顶点作为原点（例如第一个顶点）
		Vector3D& origin = *(new Vector3D(vertices[0]));

		// 从原点出发的三个向量
		Vector3D* vecA = new Vector3D(vertices[1] - origin);
		Vector3D* vecB = new Vector3D(vertices[2] - origin);
		Vector3D* vecC = new Vector3D(vertices[4] - origin);

		// 体积是这三个向量的混合积的绝对值
		Vector3D* crossAB = new Vector3D(vecA->cross(*vecB));
		double result = abs(crossAB->dot(*vecC));

		delete vecA;
		delete vecB;
		delete vecC;

		delete crossAB;
		delete& origin;

		return result;
	}
};

string decimalToString(long double value, int precision) {
	ostringstream oss;
	oss << std::fixed << std::setprecision(precision) << value;
	return oss.str();
}

void outPly(string baseFilePath = "",
	long long meshCount = 0,
	map<long long, Point> pointsMap = {},
	long long pointCount = 0,
	map<long long, Face> facesMap = {},
	long long faceCount = 0, 
	long double iStart = 1.0, 
	long double iEnd = 0.0) {

	string outfileName = baseFilePath + "_" + decimalToString((round(iStart*10)/10),1) + "_" + decimalToString((round(iEnd*10)/10),1) + "_" + to_string(meshCount) + ".ply";
	ofstream outfile(outfileName);

	outfile << "ply" << "\n";
	outfile << "format ascii 1.0" << "\n";
	outfile << "comment made by anonymous" << "\n";
	//cout << "comment this file is a cube" << endl;
	outfile << "comment  object: another cube" << "\n";
	outfile << "element vertex " << pointsMap.size() << "\n";

	outfile << "property float32 x" << "\n";
	outfile << "property float32 y" << "\n";
	outfile << "property float32 z" << "\n";
	//cout << "property red uint8" << endl;
	//cout << "property green uint8" << endl;
	//cout << "property blue uint8" << endl;
	outfile << "element face " << facesMap.size() << "\n";
	outfile << "property list uint8 int32 vertex_index" << "\n";
	outfile << "end_header" << "\n";

	for (long long i = 0; i < pointsMap.size(); i++) {
		//cout << pointsMap[i].x << " " << pointsMap[i].y << " " << pointsMap[i].z << endl;
		outfile << pointsMap[i].x << " " << pointsMap[i].y << " " << pointsMap[i].z << "\n";
	}

	for (long long i = 0; i <facesMap.size(); i++) {
		//cout << 4 << " " << facesMap[i].p1 << " " << facesMap[i].p2 << " " << facesMap[i].p3 << " " << facesMap[i].p4 << endl;
		outfile << 4 << " " << facesMap[i].p1 << " " << facesMap[i].p2 << " " << facesMap[i].p3 << " " << facesMap[i].p4 << "\n";
	}

	//刷新缓冲区，将缓冲区数据进行IO,并清空缓冲区
	outfile.flush();
	outfile.close();

}


int64_t get_timestamp() {
	auto now = std::chrono::system_clock::now();
	auto duration = now.time_since_epoch();
	auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
	return millis;
}

// 从左到右依次判断文件夹是否存在,不存在就创建
// example: /home/root/mkdir/1/2/3/4/
// 注意:最后一个如果是文件夹的话,需要加上 '\' 或者 '/'
int32_t createDirectory(const std::string& directoryPath)
{
	uint32_t dirPathLen = directoryPath.length();
	if (dirPathLen > MAX_PATH_LEN)
	{
		return -1;
	}
	char tmpDirPath[MAX_PATH_LEN] = { 0 };
	for (uint32_t i = 0; i < dirPathLen; ++i)
	{
		tmpDirPath[i] = directoryPath[i];
		if (tmpDirPath[i] == '\\' || tmpDirPath[i] == '/')
		{
			if (ACCESS(tmpDirPath, 0) != 0)
			{
				int32_t ret = MKDIR(tmpDirPath);
				if (ret != 0)
				{
					return ret;
				}
			}
		}
	}
	return 0;
}

std::string format_time(const struct tm& timeinfo) {
	// 定义一个足够大的字符数组来存储格式化后的时间字符串
	char buffer[80];

	// 使用strftime函数将tm结构体格式化为字符串
	// %H 表示24小时制的小时，%M 表示分钟，%S 表示秒
	strftime(buffer, sizeof(buffer), "%H:%M:%S", &timeinfo);

	// 将char数组转换为string并返回
	return std::string(buffer);
}

void  coutInfo(LPCTSTR info) {

	// 获取当前时间
	time_t currentTime = time(0);
	// 使用localtime_s代替localtime
	struct tm local_time;
	// 使用localtime转换为本地时间
	//std::tm* parts = localtime_s(&local_time, &now_c);

	errno_t err = localtime_s(&local_time, &currentTime);

	string time_str = "";
	// 检查localtime_s是否成功执行
	if (err == 0) {
		time_str = format_time(local_time);
	}

	// 将 std::string 转换为 LPCTSTR 以用于 MessageBox
	// 如果你的项目是 Unicode，则需要将 std::string 转换为 std::wstring
	std::wstring wString = std::wstring(time_str.begin(), time_str.end());

	LPCWSTR lpwstr = wString.c_str();

	//MessageBoxW(NULL, lpwstr, L"时间信息", MB_OK); // 对于 Unicode

	SendMessage(hListBox, LB_ADDSTRING, 0, (LPARAM)lpwstr);
	AddItemToListBox(hListBox, info);

	// 使用ostringstream进行格式化
	//std::ostringstream oss;
	//oss << std::setw(2) << std::setfill('0') << parts->tm_hour << ":"
	//	<< std::setw(2) << std::setfill('0') << parts->tm_min << ":"
	//	<< std::setw(2) << std::setfill('0') << parts->tm_sec;
	//return oss.str();
	
}


// 定义一个线程函数来更新进度条
DWORD WINAPI UpdateProgressBarThread(LPVOID lpParam)
{
	// 更新进度条的当前位置
	SendMessage(hProgressBar, PBM_SETPOS, (WPARAM)iProgressBar, 0);
	return 0;
}


string filePath = "";
string fName = to_string(get_timestamp());
//string fName = "1733206122441";//data3 点数据已处理，直接使用做拓扑数据

// 生成的网格bin文件的点集合文件
string filePathVertex = "";
// 体积34000及以上的网格
string baseFilePath = "";
// 体积400及以下的网格
string baseFilePath1 = "";

// 待赋值的变量
long long char_len, data_len;
char type, time1_type, name[128], unit[64], other[40];
double time1, Max, Min, Avg;
double* d_data = NULL;
int* i_data = NULL;

long long fileSize = 0;
long long binFileLen = 0;

set<int> countSet = {};
map<int, long long> countMap; // 创建一个map来存储每个数字及其出现的次数

//网格表面Z最大的点集合
map<string, string> poiMapXY;
map<string, string> poiMapXZ;
map<string, string> poiMapYZ;

map<string, string> poiMapXYnegative;
map<string, string> poiMapXZnegative;
map<string, string> poiMapYZnegative;

map<string, string> xyzRange;

const int sVolMin = 0;//小网格体积最小
const int sVolMax = 750;//小网格体积最大

const long long bVolMin = 1000;//大网格体积最小
const long long bVolMax = 999999999;//大网格体积最大

const long long outMeshCountChunk = 1*1000; //大网格分片打包输出的个数
const long long outMeshCountChunk1 = 1*1000;//小网格分片打包输出的个数

const int gridMultiples = 1;//网格粗化倍数参数
const int zAaxisStarts = 0;//网格切片Z轴的起始高度

bool infoTaskState = false;
bool meshTaskState = false;

void gridVtx() {
	//cout << "GRID_VTX" << ",";
	//输出txt格式的三维点集合文件
	
	ofstream fout1(filePathVertex);
	cout.rdbuf(fout1.rdbuf());

	//cout << "% x   y   z" << "\n";
	// 输出点集合到文件
	coutInfo(L"处理三维点数据...");
	iProgressBar = 0;
	
	for (long long i = 0; i < data_len; i += 3) {
		//两个整数相除，结果会被截断为整数 小数部分被丢弃了
		// 正确的做法：至少有一个操作数是浮点数
		double result_double = (static_cast<double>(i) / data_len) * 100; // 将a转换为double类型，然后进行除法

		if (result_double && (iProgressBar < result_double)) {
			iProgressBar = result_double;

			//CreateThread(NULL, 0, UpdateProgressBarThread, NULL, 0, NULL);
			// 更新进度条的当前位置
			SendMessage(hProgressBar, PBM_SETPOS, (WPARAM)result_double, 0);
		}
		cout << d_data[i] << " " << d_data[i + 1] << " " << d_data[i + 2] << endl;
	}
	
	//关闭文件流
	fout1.close();
	
	/*
	//点序列，每三个值构成点，x、y、z，每8个点构成1个六面体网格
	coutInfo(L"处理投影点集合...");
	iProgressBar = 0;
	for (long long i = 0; i < data_len; i += (3 * 8 * 1)) {

		//两个整数相除，结果会被截断为整数 小数部分被丢弃了
		// 正确的做法：至少有一个操作数是浮点数
		double result_double = (static_cast<double>(i) / data_len) * 100; // 将a转换为double类型，然后进行除法

		if (result_double && (iProgressBar < result_double)) {
			iProgressBar = result_double;

			//CreateThread(NULL, 0, UpdateProgressBarThread, NULL, 0, NULL);
			// 更新进度条的当前位置
			SendMessage(hProgressBar, PBM_SETPOS, (WPARAM)result_double, 0);
		}

		//三维坐标 x、y、z中的z值判断
		if (d_data[i + 2] > zAaxisStarts) {
			//cout << d_data[i] << " " << d_data[i + 1] << " " << d_data[i + 2] << "\n";
			//floor()和ceil()函数,还有round()函数
			long long x = floor(d_data[i]);
			//注意负数的处理
			long long y = floor(d_data[i + 1]);
			long long z = floor(d_data[i + 2]);

			if (floor(atof(xyzRange["xmin"].c_str())) > x || xyzRange["xmin"].size() == 0) {
				xyzRange["xmin"] = longToString(x);
			}
			else if (floor(atof(xyzRange["xmax"].c_str())) < x || xyzRange["xmax"].size() == 0) {
				xyzRange["xmax"] = longToString(x);
			}

			if (floor(atof(xyzRange["ymin"].c_str())) > y || xyzRange["ymin"].size() == 0) {
				xyzRange["ymin"] = longToString(y);
			}
			else if (floor(atof(xyzRange["ymax"].c_str())) < y || xyzRange["ymax"].size() == 0) {
				xyzRange["ymax"] = longToString(y);
			}

			if (floor(atof(xyzRange["zmin"].c_str())) > z || xyzRange["zmin"].size() == 0) {
				xyzRange["zmin"] = longToString(z);
			}
			else if (floor(atof(xyzRange["zmax"].c_str())) < z || xyzRange["zmax"].size() == 0) {
				xyzRange["zmax"] = longToString(z);
			}

			// 控制 xy 平面网格的疏密程度
			string xykey = longToString((x / 10) * 10) + "_" + longToString((y / 10) * 10);
			//cout << x << "-" << y<<"-" << z <<"_" << key << endl;
			if (poiMapXY.find(xykey) == poiMapXY.end()) {
				poiMapXY[xykey] = longToString((z / 1) * 1);
				//cout << poiMapXY[key] << endl;
				poiMapXYnegative[xykey] = longToString((z / 1) * 1);
			}
			else {

				//cout << poiMapXY[key] << endl;
				if (z > strtoll(poiMapXY[xykey].c_str(), NULL, 10)) {
					poiMapXY[xykey] = longToString((z / 1) * 1); // 如果数字已经在map中，且当前的z比他大，就重新赋值
				}
				else if (z < strtoll(poiMapXY[xykey].c_str(), NULL, 10)) {
					poiMapXYnegative[xykey] = longToString((z / 1) * 1);
				}
			}

			// 控制 xz 平面网格的疏密程度
			string xzkey = longToString((x / 10) * 10) + "_" + longToString((z / 10) * 10);
			//cout << x << "-" << y<<"-" << z <<"_" << key << endl;
			if (poiMapXZ.find(xzkey) == poiMapXZ.end()) {
				poiMapXZ[xzkey] = longToString((y / 1) * 1);
				//cout << poiMapXZ[xzkey] << endl;
				poiMapXZnegative[xzkey] = longToString((y / 1) * 1);
			}
			else {
				//cout << poiMapXZ[xzkey] << endl;
				if (y > strtoll(poiMapXZ[xzkey].c_str(), NULL, 10)) {
					poiMapXZ[xzkey] = longToString((y / 1) * 1); // 如果数字已经在map中，且当前的z比他大，就重新赋值
				}
				else if (y < strtoll(poiMapXZ[xzkey].c_str(), NULL, 10)) {
					poiMapXZnegative[xzkey] = longToString((y / 1) * 1);
				}
			}

			// 控制 yz 平面网格的疏密程度
			string yzkey = longToString((y / 10) * 10) + "_" + longToString((z / 10) * 10);
			//cout << x << "-" << y<<"-" << z <<"_" << key << endl;
			if (poiMapYZ.find(yzkey) == poiMapYZ.end()) {
				poiMapYZ[yzkey] = longToString((x / 1) * 1);
				//cout << poiMapYZ[yzkey] << endl;
				poiMapYZnegative[yzkey] = longToString((x / 1) * 1);
			}
			else {
				//cout << poiMapYZ[yzkey] << endl;
				if (x > strtoll(poiMapYZ[yzkey].c_str(), NULL, 10)) {
					poiMapYZ[yzkey] = longToString((x / 1) * 1); // 如果数字已经在map中，且当前的z比他大，就重新赋值
				}
				else if (x < strtoll(poiMapYZ[yzkey].c_str(), NULL, 10)) {
					poiMapYZnegative[yzkey] = longToString((x / 1) * 1);
				}
			}

		}


	}

	*/



	//cout << "\n";

	// 输出网格表面最大值的筛选结果
	/*
	cout << "% x   y   z" << "\n";
	for (const auto& pair : poiMapXY) {
		string s = pair.first;

		vector<string> tokens;
		string token;
		stringstream ss(s);
		while (getline(ss, token, '_')) {
			if (!token.empty()) {
				tokens.push_back(token);
			}				}
		if (tokens.size()==2) {
			cout << tokens[0] << " " << tokens[1] << " " << pair.second << "\n";
		}

	}*/

	//return 0;

	//网格尺寸信息

	//合并成一個網格文件輸出
	ofstream fout("outfile" + fName + "\\info_xyz_range.txt");
	cout.rdbuf(fout.rdbuf());

	for (const auto& pair : xyzRange) {
		cout << " " << pair.first << ": " << pair.second << " " << endl;
	}

	/*
	for (const auto& pair : poiMapXY) {
		cout << " " << pair.first << ": " << pair.second << " " << endl;
	}
	for (const auto& pair : poiMapXZ) {
		cout << " " << pair.first << ": " << pair.second << " " << endl;
	}
	for (const auto& pair : poiMapYZ) {
		cout << " " << pair.first << ": " << pair.second << " " << endl;
	}
	*/

	//return 0;
}

// 如果你的项目使用的是宽字符（通常是Unicode）
LPCTSTR StringToLPCTSTR(const std::string& str) {
	// 将std::string转换为LPCWSTR
	const size_t cchWideChar = str.length() + 1;
	size_t cchConverted = 0;
	wchar_t* lpwstr = new wchar_t[cchWideChar];
	mbstowcs_s(&cchConverted, lpwstr, cchWideChar, str.c_str(), _TRUNCATE);

	return lpwstr;
}


void meshNodeList(long double iStart=1.0, long double iEnd=0.0) {

	map<long long, Face> facesMap = {};
	map<long long, Point> pointsMap = {};

	atomic<long long> pointCount = 0;
	atomic<long long> faceCount = 0;

	atomic<long long> meshCount = 0;
	atomic<long long> outMeshCount = 0;


	map<long long, Face> facesMap1 = {};
	map<long long, Point> pointsMap1 = {};

	atomic<long long> pointCount1 = 0;
	atomic<long long> faceCount1 = 0;

	atomic<long long> meshCount1 = 0;
	atomic<long long> outMeshCount1 = 0;


	filebuf* pbuf;
	ifstream filestr;
	long long filesize;
	char* buffer;
	// 要读入整个文件，必须采用二进制打开 
	filestr.open(filePathVertex, ios::binary);
	// 获取filestr对应buffer对象的指针 
	pbuf = filestr.rdbuf();
	// 调用buffer对象方法获取文件大小
	filesize = pbuf->pubseekoff(0, ios::end, ios::in);
	pbuf->pubseekpos(0, ios::in);
	// 分配内存空间
	buffer = new char[filesize];
	// 获取文件内容
	pbuf->sgetn(buffer, filesize);
	filestr.close();
	// 输出到标准输出
	//cout.write(buffer, filesize);

	const char delims[] = "\n";
	char* result = NULL;
	char* ptr = NULL;
	result = strtok_s(buffer, delims, &ptr);
	vector<char*> res_split;//存储分割后的字符串
	while (result != NULL) {
		//cout<<result<<endl;
		res_split.push_back(result);
		result = strtok_s(NULL, delims, &ptr);
	}
	//cout << res_split.at(2) << endl;
	//delete[]buffer;

	//cout << "NODE_LIST" << ",";
	// 编号从1开始，8个顶点的顺序是先排底面、再排顶面，面内逆时针排序。
	// 创建一个立方体 
	//    v8----- v7
	//   /|      /|
	//  v5------v6|
	//  | |     | |
	//  | |v4---|-|v3
	//  |/      |/
	//  v1------v2
	/*
	//创建立方体的顶点
	vertices = [
		new THREE.Vector3(10, 10, 10), //v0
		new THREE.Vector3(-10, 10, 10), //v1
		new THREE.Vector3(-10, -10, 10), //v2
		new THREE.Vector3(10, -10, 10), //v3
		new THREE.Vector3(10, -10, -10), //v4
		new THREE.Vector3(10, 10, -10), //v5
		new THREE.Vector3(-10, 10, -10), //v6
		new THREE.Vector3(-10, -10, -10) //v7
	];*/
	//立方体的面
	/*int faceIndex[36] = {
		0, 1, 2,
		0, 2, 3,
		0, 3, 4,
		0, 4, 5,
		1, 6, 7,
		1, 7, 2,
		6, 5, 4,
		6, 4, 7,
		5, 6, 1,
		5, 1, 0,
		3, 2, 7,
		3, 7, 4
	};*/
	/**long long len = data_len - 160008;
	for (long long i = 0; i < len; i += 160000) {
		long long tempArr[8] = { d_data[i],d_data[i + 1],d_data[i + 2],d_data[i + 3],d_data[i + 4],d_data[i + 5],d_data[i + 6],d_data[i + 7] };
		for (int k = 0; k < 36; k += 3) {
			cout << 3 << " " << fixed << setprecision(5) << tempArr[faceIndex[k]] << " " << tempArr[faceIndex[k + 1]] << " " << tempArr[faceIndex[k + 2]] << " " << endl;
		}
	}*/

	int faceIndex[24] = {
		0,1,2,3,
		4,5,6,7,
		0,3,7,4,
		1,2,6,5,
		0,1,5,4,
		2,6,7,3
	};
	long long len = data_len - 8;
	//从下往上切片
	//for (long long i = 0; i < len; i += (8 * 1)) {


	//从上往下切片
	coutInfo(L"处理拓扑数据...");
	iProgressBar = 0;
	long long step = (static_cast<long long>(8) * gridMultiples);
	long long start = (((len - step) * iStart)*8)/8;
	long long end = (((len - step) * iEnd)*8)/8;
	
	for (long long i = start; i > end; i -= step) {

		// 两个整数相除，结果会被截断为整数 小数部分被丢弃了
		// 正确的做法：至少有一个操作数是浮点数
		double result_double = 100.0 - (static_cast<double>(i - end) / static_cast<double>(start - end)) * 100.0; // 将a转换为double类型，然后进行除法

		if (result_double && (iProgressBar < result_double)) {
			iProgressBar = result_double;

			//CreateThread(NULL, 0, UpdateProgressBarThread, NULL, 0, NULL);
			// 更新进度条的当前位置
			SendMessage(hProgressBar, PBM_SETPOS, (WPARAM)result_double, 0);
		}

		long long tempArr[8] = { 0,0,0,0,0,0,0,0 };
		if (gridMultiples == 1) {
			tempArr[0] = d_data[i];
			tempArr[1] = d_data[i + 1];
			tempArr[2] = d_data[i + 2];
			tempArr[3] = d_data[i + 3];
			tempArr[4] = d_data[i + 4];
			tempArr[5] = d_data[i + 5];
			tempArr[6] = d_data[i + 6];
			tempArr[7] = d_data[i + 7];
		}
		else {
			tempArr[0] = d_data[i];
			tempArr[1] = d_data[i + 1 + 8 * gridMultiples];
			tempArr[2] = d_data[i + 2 + 8 * gridMultiples];
			tempArr[3] = d_data[i + 3 + 0 * gridMultiples];
			tempArr[4] = d_data[i + 4 + 0 * gridMultiples];
			tempArr[5] = d_data[i + 5 + 8 * gridMultiples];
			tempArr[6] = d_data[i + 6 + 8 * gridMultiples];
			tempArr[7] = d_data[i + 7 + 0 * gridMultiples];
		}

		// 定义8个顶点
		//vector<Vector3D> vertices = {
		//	{pointsMax[tempArr[0]].x, pointsMax[tempArr[0]].y, pointsMax[tempArr[0]].z},   // 顶点1
		//	{pointsMax[tempArr[1]].x, pointsMax[tempArr[1]].y, pointsMax[tempArr[1]].z},   // 顶点2
		//	{pointsMax[tempArr[2]].x, pointsMax[tempArr[2]].y, pointsMax[tempArr[2]].z},   // 顶点3
		//	{pointsMax[tempArr[3]].x, pointsMax[tempArr[3]].y, pointsMax[tempArr[3]].z},   // 顶点4
		//	{pointsMax[tempArr[4]].x, pointsMax[tempArr[4]].y, pointsMax[tempArr[4]].z},   // 顶点5
		//	{pointsMax[tempArr[5]].x, pointsMax[tempArr[5]].y, pointsMax[tempArr[5]].z},   // 顶点6
		//	{pointsMax[tempArr[6]].x, pointsMax[tempArr[6]].y, pointsMax[tempArr[6]].z},   // 顶点7
		//	{pointsMax[tempArr[7]].x, pointsMax[tempArr[7]].y, pointsMax[tempArr[7]].z}    // 顶点8
		//};

		vector<Vector3D> vertices = {};

		bool meshFaceTop = false;

		for (int l = 0; l < 8; l++) {

			string str = res_split.at(tempArr[l]);
			vector<string> strList;
			strSplit(str, ' ', strList);
			//cout << strList[0] << endl

			string x = strList[0];
			string y = strList[1];
			string z = strList[2];

			//vertices.push_back({ atof(x.c_str()),atof(y.c_str()),atof(z.c_str()) });
			//cout << x << "-" << y <<"-" << z << endl;
			// 控制分层切片的范围
			if (floor(atof(z.c_str())) > zAaxisStarts) {
				//cout << d_data[i] << " " << d_data[i + 1] << " " << d_data[i + 2] << "\n";
				//floor()和ceil()函数,还有round()函数
				long long x1 = floor(atof(x.c_str()));
				//注意负数的处理
				long long y1 = floor(atof(y.c_str()));
				long long z1 = floor(atof(z.c_str()));

				// 控制 xy 平面网格的疏密程度
				string xykey = longToString((x1 / 10) * 10) + "_" + longToString((y1 / 10) * 10);

				// 控制 xy 平面网格的疏密程度
				string xzkey = longToString((x1 / 10) * 10) + "_" + longToString((z1 / 10) * 10);

				// 控制 xy 平面网格的疏密程度
				string yzkey = longToString((y1 / 10) * 10) + "_" + longToString((z1 / 10) * 10);

				meshFaceTop = true;//网格全量輸出，跳过下面的抽壳筛选

				/*
				if (poiMapXY.find(xykey) == poiMapXY.end()) {
					//当前网格不在map里面
					//meshFaceTop = false;
				}
				else if (poiMapXZ.find(xzkey) == poiMapXZ.end()) {
					//当前网格不在map里面
					//meshFaceTop = false;
				}
				else if (poiMapYZ.find(yzkey) == poiMapYZ.end()) {
					//当前网格不在map里面
					//meshFaceTop = false;
				}
				else {
					//cout << xykey << endl;
					//当前网格在map里面 且z轴高度比之前的高
					if (z1 > strtoll(poiMapXY[xykey].c_str(), NULL, 10)) {
						meshFaceTop = true;
					}
					else if (x1 > strtoll(poiMapYZ[yzkey].c_str(), NULL, 10)) {
						meshFaceTop = true;
					}
					else if (y1 > strtoll(poiMapXZ[xzkey].c_str(), NULL, 10)) {
						meshFaceTop = true;
					}
					else if (z1 < strtoll(poiMapXYnegative[xykey].c_str(), NULL, 10)) {
						meshFaceTop = true;
					}
					else if (y1 < strtoll(poiMapXZnegative[xzkey].c_str(), NULL, 10)) {
						meshFaceTop = true;
					}
					else if (x1 < strtoll(poiMapYZnegative[yzkey].c_str(), NULL, 10)) {
						meshFaceTop = true;
					}
				}

				*/
			}
		}

		//控制模型的输出数据，可以打包所有网格一个ply文件，也可以每个小网格单独文件输出
		if (meshFaceTop) {
			for (int l = 0; l < 8; l++) {

				string str = res_split.at(tempArr[l]);
				vector<string> strList;
				strSplit(str, ' ', strList);
				//cout << strList[0] << endl
				string x = strList[0];
				string y = strList[1];
				string z = strList[2];

				vertices.push_back({ atof(x.c_str()),atof(y.c_str()),atof(z.c_str()) });
				//cout << x << "-" << y <<"-" << z << endl;

			}

			// 创建六面体对象 在堆上实例化 
			Hexahedron* myHexahedron = new Hexahedron(vertices);

			long long volume = round(myHexahedron->getVolume());

			// 输出体积
			//cout << "六面体体积Volume: " << volume << "，Type of a: " << typeid(volume).name() << endl;
			// 插入单个元素

			// 判断网格的体积是否大于400或者34000
			if (volume >= bVolMin && volume <= bVolMax) {
				// 根据采样参数 100 或 1000 处理输出网格数量
				if (!(meshCount % 1)) {

					//endl的目的是让用户可以在合理的时间点刷新文件。
					//打印\n不会(必然)刷新输出，而打印endl或flush则会。
					//如果您想要快速写入，并且在完成之前并不关心数据是否在那里，
					//那么使用\n完成所有的写入，不用担心(因为closing the file也会刷新流)，如果您仍然没有获得想要的性能，
					//那么可以使用fstream::read(char*, int) --它允许您以所需的任何大小的块读取数据(尝试更大的块)。

					for (int m = 0; m < 8; m++) {

						long long x = vertices[m].x;
						long long y = vertices[m].y;
						long long z = vertices[m].z;
						pointsMap.insert(pair<long long, Point>(pointCount, Point(x, y, z)));

						//outfile << x << " " << y << " " << z << "\n";

						//统计模型的所有点
						pointCount++;

						//cout << x << " " << y << " " << z << "\n";

					}

					for (int k = 0; k < 24; k += 4) {
						//cout << (pointIndex - 8) + faceIndex[k]<< " " << (pointIndex - 8) + faceIndex[k + 1]<< " " << (pointIndex - 8) + faceIndex[k + 2]<< " " << (pointIndex - 8) + faceIndex[k + 3] << endl;
						//cout << 4 << " " << fixed << setprecision(5) << tempArr[faceIndex[k]] << " " << tempArr[faceIndex[k + 1]] << " " << tempArr[faceIndex[k + 2]] << " " << tempArr[faceIndex[k + 3]] << endl;
						facesMap.insert(pair<long long, Face>(faceCount, Face((pointCount - 8) + faceIndex[k], (pointCount - 8) + faceIndex[k + 1], (pointCount - 8) + faceIndex[k + 2], (pointCount - 8) + faceIndex[k + 3])));

						//outfile << 4 << " " << faceIndex[k] << " " << faceIndex[k + 1] << " " << faceIndex[k + 2] << " " << faceIndex[k + 3] << "\n";

						//统计模型的所有面
						faceCount++;

					}
					//刷新缓冲区，将缓冲区数据进行IO,并清空缓冲区
					//outfile.flush();
					//outfile.close();

					//每10000个网格打包输出
					if (!(outMeshCount % outMeshCountChunk) && outMeshCount != 0) {

						outPly(baseFilePath, meshCount, pointsMap, pointCount, facesMap, faceCount, iStart, iEnd);

						//清空数据，待重新装填
						pointsMap.clear();
						facesMap.clear();

						pointCount = 0;
						faceCount = 0;

						//return 0;
					}

					outMeshCount++;
				}

				//8个点构成一个网格，统计所有网格数量
				meshCount++;

			}

			// 判断网格的体积是否大于400或者34000
			if (volume >= sVolMin && volume <= sVolMax) {
				// 根据采样参数 100 或 1000 处理输出网格数量
				if (!(meshCount1 % 1)) {

					//endl的目的是让用户可以在合理的时间点刷新文件。
					//打印\n不会(必然)刷新输出，而打印endl或flush则会。
					//如果您想要快速写入，并且在完成之前并不关心数据是否在那里，
					//那么使用\n完成所有的写入，不用担心(因为closing the file也会刷新流)。
					//如果您仍然没有获得想要的性能，那么可以使用fstream::read(char*, int) --它允许您以所需的任何大小的块读取数据(尝试更大的块)。


					for (int m = 0; m < 8; m++) {

						long long x = vertices[m].x;
						long long y = vertices[m].y;
						long long z = vertices[m].z;
						pointsMap1.insert(pair<long long, Point>(pointCount1, Point(x, y, z)));

						//outfile << x << " " << y << " " << z << "\n";

						//统计模型的所有点
						pointCount1++;

						//cout << x << " " << y << " " << z << "\n";

					}

					for (int k = 0; k < 24; k += 4) {
						//cout << (pointIndex - 8) + faceIndex[k]<< " " << (pointIndex - 8) + faceIndex[k + 1]<< " " << (pointIndex - 8) + faceIndex[k + 2]<< " " << (pointIndex - 8) + faceIndex[k + 3] << endl;
						//cout << 4 << " " << fixed << setprecision(5) << tempArr[faceIndex[k]] << " " << tempArr[faceIndex[k + 1]] << " " << tempArr[faceIndex[k + 2]] << " " << tempArr[faceIndex[k + 3]] << endl;
						facesMap1.insert(pair<long long, Face>(faceCount1, Face((pointCount1 - 8) + faceIndex[k], (pointCount1 - 8) + faceIndex[k + 1], (pointCount1 - 8) + faceIndex[k + 2], (pointCount1 - 8) + faceIndex[k + 3])));

						//outfile << 4 << " " << faceIndex[k] << " " << faceIndex[k + 1] << " " << faceIndex[k + 2] << " " << faceIndex[k + 3] << "\n";

						//统计模型的所有面
						faceCount1++;

					}
					//刷新缓冲区，将缓冲区数据进行IO,并清空缓冲区
					//outfile.flush();
					//outfile.close();

					//每10000个网格打包输出
					if (!(outMeshCount1 % outMeshCountChunk1) && outMeshCount1 != 0) {

						outPly(baseFilePath1, meshCount1, pointsMap1, pointCount1, facesMap1, faceCount1, iStart, iEnd);

						//清空数据，待重新装填
						pointsMap1.clear();
						facesMap1.clear();

						pointCount1 = 0;
						faceCount1 = 0;

						//return 0;
					}

					outMeshCount1++;
				}

				//8个点构成一个网格，统计所有网格数量
				meshCount1++;

			}

			countSet.insert(volume);
			countMap[volume]++; // 如果数字已经在map中，其对应的值增加1，否则插入新条目并初始化为1

			/*
			if ((!countMap.empty())&&countMap.size()>3){
				//动态调整最大最小网格体积筛选的阈值
				map<int, long long>::const_iterator itmax = extremeValueAnalysis(countMap, "value", "max");
				//cout << itmax->first << "_" << itmax->second << endl;

				//if (sVolMax < itmax->first) {
				//	sVolMax = itmax->first;
				//}

				//map<int, long long>::const_iterator itmin = extremeValueAnalysis(countMap, "value", "min");
				//cout << itmin->first << "_" << itmin->second << endl;
				//if (sVolMin > itmin->first) {
				//	sVolMin = itmin->first;
				//}

				vector< pair<int, long long> > v(countMap.begin(), countMap.end());//利用vector容器储存后再进行排序。
				sort(v.begin(), v.end(), cmp_value);//按 value 的从大到小排序的函数
				//for (vector< pair<int, long long> >::iterator it = v.begin(); it != v.end(); ++it){
				//	cout << it->first << " " << it->second << endl;
				//}
				auto it = v.begin();//获取第一个元素
				++it;//移动迭代器到第二个元素
				//cout << it->first << "_" << it->second << endl;//输出第二个元素
				//bVolMax = it->first;
			}
			*/
			vector<Vector3D>().swap(vertices);
			//vertices.clear();
			//memset((void*)&vertices, 0x0, sizeof(vertices));

			myHexahedron->~Hexahedron();
			//释放类实例的内存
			delete myHexahedron;
		}

		//网格体积分布
		//400 34000 2040000
		//400 800 1200 1600 2000 2400 2800 4000 
		//24000 32800 33200 33600 34000 34400 2040000

		//400 出现 1081253 次。
		//34000 出现 12786 次。

	}
	//cout << endl;

	//return 0;

	if (countSet.size() != 0 && countMap.size() != 0) {

		ofstream fout2("outfile" + fName + "\\info_count_mesh_type.txt");
		cout.rdbuf(fout2.rdbuf());

		// 使用迭代器遍历set
		for (set<int>::iterator it = countSet.begin(); it != countSet.end(); ++it) {
			cout << *it << " ";
		}

		cout << endl;

		// 输出每个数字及其出现的次数
		for (const auto& pair : countMap) {
			cout << "volume:" << pair.first << ",count:" << pair.second << endl;
		}

		//刷新缓冲区，将缓冲区数据进行IO,并清空缓冲区
		fout2.close();

		if (pointsMap.size() != 0 && facesMap.size() != 0) {

			outPly(baseFilePath, meshCount, pointsMap, pointCount, facesMap, faceCount, iStart, iEnd);

			//清空数据，待重新装填
			pointsMap.clear();
			facesMap.clear();

			pointCount = 0;
			faceCount = 0;

		}



		if (pointsMap1.size() != 0 && facesMap1.size() != 0) {

			outPly(baseFilePath1, meshCount1, pointsMap1, pointCount1, facesMap1, faceCount1, iStart, iEnd);

			//清空数据，待重新装填
			pointsMap1.clear();
			facesMap1.clear();

			pointCount1 = 0;
			faceCount1 = 0;

		}


	}
}


int runTask()
{
	
	//模拟器输出的静态、动态网格bin文件
	//string filePath = "F:\\data\\data0\\SPE10_geom.bin";
	//打开文件 对话框，选择文件并显示文件的路径
	filePath = binFilePath;
	fileSize = getBinSize(filePath);
	binFileLen = fileSize;
	//fName = to_string(get_timestamp());

	// 生成的网格bin文件的点集合文件
	filePathVertex = "outfile" + fName + "\\vertex\\data.txt";
	// 体积34000及以上的网格
	baseFilePath = "outfile" + fName + "\\ply_batch\\b_";
	// 体积400及以下的网格
	baseFilePath1 = "outfile" + fName + "\\ply_batch\\s_";

	createDirectory("outfile" + fName + "\\vertex\\");
	createDirectory("outfile" + fName + "\\ply_batch\\");

	pair<string, string> p1 = make_pair("xmin", "");
	xyzRange.insert(p1);
	pair<string, string> p2 = make_pair("xmax", "");
	xyzRange.insert(p2);
	pair<string, string> p3 = make_pair("ymin", "");
	xyzRange.insert(p3);
	pair<string, string> p4 = make_pair("ymax", "");
	xyzRange.insert(p4);
	pair<string, string> p5 = make_pair("zmin", "");
	xyzRange.insert(p5);
	pair<string, string> p6 = make_pair("zmax", "");
	xyzRange.insert(p6);

	//生成的网格bin文件的点集合文件
	//filePathVertex = "G:\\hisim-3d\\test\\vertex\\data0-1.txt";
	// 体积34000及以上的网格
	//baseFilePath = "G:\\hisim-3d\\test\\outfile3\\ply_batch\\b_";
	// 体积400及以下的网格
	//baseFilePath1 = "G:\\hisim-3d\\test\\outfile3\\ply_batch\\s_";

	// 打开二进制文件
	ifstream fp(filePath, ios::binary);

	if (!fp.is_open()) {
		cerr << "无法打开文件" << endl;
		return 1;  // 返回错误代码
	}

	//合并成一個網格文件輸出
	ofstream fout("outfile" + fName + "\\info.txt");
	streambuf* pOld = std::cout.rdbuf(fout.rdbuf());

	cout << "读取bin格式网格文件 \"" << filePath << "\"" << endl;
	cout << "网格bin文件字节数：" << fileSize << " byte" << endl;

	//只输出网格数据概览信息
	if (!OutputsMeshInformation) {

		cout << "char_len" << ",";
		cout << "time" << ",";
		cout << "type" << ",";
		cout << "name" << ",";
		cout << "unit" << ",";
		cout << "data_len" << ",";
		cout << "time_type" << ",";
		cout << "d_data" << ",";
		cout << "i_data" << endl;

	}

	
	while (binFileLen > 8) {
		// 解读静、动态网格参数文件的基本方法是，用二进制只读方式打开文件，
		// 先读取8个字节，转化为int64型，得到“接下来内容的总字节数L”，
		// 读取接下来的L个字节，得到数组头和数组内容；
		// 再读取8个字节，进入下一个数组的读取。
		// 以下读取数组头
		fp.read((char*)&char_len, sizeof(long long));

		if (char_len) {
			binFileLen = binFileLen - char_len - 8;

			fp.read((char*)&time1, sizeof(double));
			fp.read((char*)&type, sizeof(char));
			fp.read(name, 128);
			fp.read(unit, 64);
			fp.read((char*)&Max, sizeof(double));
			fp.read((char*)&Min, sizeof(double));
			fp.read((char*)&Avg, sizeof(double));
			fp.read(other, 40);
			time1_type = other[0];

			// 以下读取数组内容
			if (type == 'd') {
				//双精度数组
				data_len = (char_len - 265) / sizeof(double);
				d_data = new double[data_len];
				fp.read((char*)d_data, char_len - 265);
			}
			else if (type == 'i') {
				//整型数组
				data_len = (char_len - 265) / sizeof(int);
				i_data = new int[data_len];
				fp.read((char*)i_data, char_len - 265);
			}

			//只输出网格数据概览信息
			if (!OutputsMeshInformation) {
				cout << char_len << ",";
				cout << time1 << ",";
				cout << type << ",";
				cout << name << ",";
				cout << unit << ",";
				cout << data_len << ",";
				cout << time1_type << ",";
				cout << d_data << ",";
				cout << i_data << endl;

			}

			string str(name);
			str = name;

			//HiSim模拟器只输出有效网格的数据，排列顺序是I循环最快、J循环其次、K循环最慢，
			//如果有无效网格则跳过不输出，数组内容的长度等于有效网格数。
			//当模型包含加密区时，数据遵循的顺序是：粗网格在加密网格前，加密网格数据按加密区内部的I、J、K顺序放置，多个加密区依次放置。

			//网格几何数据是“Brick”格式，该格式包含“点集 + 拓扑”，可以描述结构或非结构的六面体单元，且单元顶点不需要是对齐的。Brick格式包含两个数组：
			//① 点集坐标，是顶点的(x, y, z)坐标，是double数组，长度等于“顶点数×3”，重合的点记为一个点；
			//② 网格顶点在点集中的编号，即每个网格由哪8个顶点组成，是整型数组，数组长度等于“有效基质网格数×8”，编号从1开始，8个顶点的顺序如图 1，顶点先排底面、再排顶面，面内逆时针排序。
			//HiSim模拟器输出的文件中，“点集坐标”名为“GRID_VTX”，网格顶点编号名为“NODE_LIST”

			//可以通过顶点共用的情况，判断网格的公共面、模型的外表面：
			//如果一个面的四个顶点既是网格A的顶点，也是网格B的顶点，则这个面是网格A、B的公共面，属于模型内部的面，反之这个面是模型的外表面。

			//网格几何数据“Brick”格式点集坐标信息 
			if (str == "GRID_VTX" && OutputsMeshInformation) {
				//int coreCount = get_core_count();
				thread thGridVtx = thread(gridVtx);
				thGridVtx.join();
			}


			//网格几何数据“Brick”格式顶点编号拓扑信息
			if (str == "NODE_LIST" && OutputsMeshInformation) {
				//int coreCount = get_core_count();
				/*thread thMeshNodeList1 = thread(meshNodeList,1.0,0.8);
				thread thMeshNodeList2 = thread(meshNodeList, 0.8, 0.6);
				thread thMeshNodeList3 = thread(meshNodeList, 0.6, 0.4);
				thread thMeshNodeList4 = thread(meshNodeList, 0.4, 0.2);
				thread thMeshNodeList5 = thread(meshNodeList, 0.2, 0.0);
				thMeshNodeList1.join();
				thMeshNodeList2.join();
				thMeshNodeList3.join();
				thMeshNodeList4.join();
				thMeshNodeList5.join();*/

				const int numThreads = 2; // 想要创建的线程数量
				std::thread threads[numThreads]; // 创建线程数组

				// 启动所有线程
				for (int i = 0; i < numThreads; ++i) {
					threads[i] = std::thread(meshNodeList, 1.0 - static_cast<long double> (i)*(1.0 / static_cast<long double> (numThreads)), 1.0 - (static_cast<long double> (i)+1)*(1.0 / static_cast<long double> (numThreads)));
					//threads[i] = std::thread(meshNodeList, 1.0, 0.0);
				}

				// 等待所有线程完成
				for (int i = 0; i < numThreads; ++i) {
					threads[i].join();
				}

				iProgressBar = 100;
				CreateThread(NULL, 0, UpdateProgressBarThread, NULL, 0, NULL);

				if (iProgressBar == 100) {

					fout.flush();
					fout.close();

					coutInfo(L"切片任务结束。");
					CString strInfo;
					//strInfo.Format(_T("整数：%04d，浮点数：%08.2f，字符串：%s"), 10, 3.14, _T("TEST"));
					char c[300];
					strcpy_s(c, fName.c_str());
					strInfo.Format(_T("%s"), CStringW(c));
					MessageBox(
						NULL,
						"切片任务已完成，可到文件夹 outfile" + strInfo + " 查阅。",
						L"信息提示",
						MB_ICONASTERISK | MB_OK
					);
					meshTaskState = false;
				}

			}

			if (type == 'd') {
				//双精度数组
				// 释放动态分配的数组内存
			    delete[] d_data;
			}
			else if (type == 'i') {
				//整型数组
				// 释放动态分配的数组内存
			    delete[] i_data;
			}


			if (fp.fail()) {  // 检查文件是否成功读取
				cerr << "错误读取文件\n";
				return 1;
			}
		}
		else {
			binFileLen = 0;
		}


	}

	fp.close();

	if (!OutputsMeshInformation) {
		iProgressBar = 100;
		CreateThread(NULL, 0, UpdateProgressBarThread, NULL, 0, NULL);

		if (iProgressBar == 100) {

			fout.flush();
	        fout.close();

			coutInfo(L"信息任务结束。");
			CString strInfo;
			//strInfo.Format(_T("整数：%04d，浮点数：%08.2f，字符串：%s"), 10, 3.14, _T("TEST"));
			char c[300];
			strcpy_s(c, fName.c_str());
			strInfo.Format(_T("%s"), CStringW(c));
			MessageBox(
				NULL,
				"信息任务已完成，可到文件夹 outfile" + strInfo + " 查阅。",
				L"信息提示",
				MB_ICONASTERISK | MB_OK
			);
			infoTaskState = false;
		}
	}

	return 0;

}


void infoTask() {
	
	try
	{
		infoTaskState = true;
		OutputsMeshInformation = false;//只输出网格信息

		iProgressBar = 0;
		CreateThread(NULL, 0, UpdateProgressBarThread, NULL, 0, NULL);
		coutInfo(L"信息任务开始...");

		runTask();

	}
	catch (...)
	{
		// 处理其他未知类型异常
		AfxMessageBox(_T("Unknown exception caught!"));
	}
}

void meshTask() {
	
	try
	{
		meshTaskState = true;
		OutputsMeshInformation = true;//网格模型切片输出

		iProgressBar = 0;
		CreateThread(NULL, 0, UpdateProgressBarThread, NULL, 0, NULL);
		coutInfo(L"切片任务开始...");

		runTask();

	}
	catch (...)
	{
		// 处理其他未知类型异常
		AfxMessageBox(_T("Unknown exception caught!"));
	}
}


int DisplayResourceNAMessageBox()
{
	int msgboxID = MessageBox(
		NULL,
		(LPCWSTR)L"Resource not available\nDo you want to try again?",
		(LPCWSTR)L"Account Details",
		MB_ICONWARNING | MB_CANCELTRYCONTINUE | MB_DEFBUTTON2
	);

	switch (msgboxID)
	{
	case IDCANCEL:
		// TODO: add code
		break;
	case IDTRYAGAIN:
		// TODO: add code
		break;
	case IDCONTINUE:
		// TODO: add code
		break;
	}

	return msgboxID;
}


//
//  函数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目标: 处理主窗口的消息。
//
//  WM_COMMAND  - 处理应用程序菜单
//  WM_PAINT    - 绘制主窗口
//  WM_DESTROY  - 发送退出消息并返回
//
//

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static HBITMAP hBitmap; // 图片句柄
	switch (message)
	{
	case WM_CLOSE:
		DestroyWindow(hWnd);//发送宁一个消息WM_DESTROY
		break;
	case WM_DESTROY:
		// 在窗口销毁时删除位图资源
		DeleteObject(hBitmap);
		PostQuitMessage(0);
		break;
	case WM_CREATE:
		// 在窗口创建时加载位图资源
		hBitmap = (HBITMAP)LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_BITMAP1));

		break;
	case WM_COMMAND:
	{
		int wmId = LOWORD(wParam);
		
		// 分析菜单选择:
		switch (wmId)
		{
		case IDM_ABOUT:
			DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
			break;
		case IDM_EXIT:
			//退出软件
			DisplayConfirmSaveAsMessageBox(hWnd);
			break;
		case IDC_BROWSE_BUTTON:
			// 处理按钮点击事件
			//打开文件 对话框，选择文件并显示文件的路径
			//if (OnOpenBinFile(hWnd)) {
			//};
			OnOpenBinFile(hWnd);
			break;
		case IDC_INFO_BUTTON:
			// 处理按钮点击事件
			//DisplayResourceNAMessageBox();
			{
				
				DWORD currentTime = GetTickCount64();

				if (meshTaskState) {
					CString strInfo;
					//strInfo.Format(_T("整数：%04d，浮点数：%08.2f，字符串：%s"), 10, 3.14, _T("TEST"));
					char c[300];
					strcpy_s(c, fName.c_str());
					strInfo.Format(_T("%s"), CStringW(c));
					MessageBox(
						NULL,
						"切片任务正在进行中...，\n 可到文件夹 outfile" + strInfo + " 检查输出的切片文件。",
						L"信息提示",
						MB_ICONASTERISK | MB_OK
					);
					return 0;
				}

				// 检查是否超过了防抖时间间隔
				if (currentTime - lastClickTime > DEBOUNCE_INTERVAL) {
					// 更新上次点击时间
					lastClickTime = currentTime;
					// 执行按钮点击的逻辑
					
					if (infoTaskState && iProgressBar != 100) {
						CString strInfo;
						//strInfo.Format(_T("整数：%04d，浮点数：%08.2f，字符串：%s"), 10, 3.14, _T("TEST"));
						char c[300];
						strcpy_s(c, fName.c_str());
						strInfo.Format(_T("%s"), CStringW(c));
						MessageBox(
							NULL,
							"信息任务正在进行中...，\n 可到文件夹 outfile" + strInfo + " 检查输出的信息文件。",
							L"信息提示",
							MB_ICONASTERISK | MB_OK
						);
					}
					else {

						
						CString cst = getEditText(hEdit);
						if (!(cst.IsEmpty())) {
							binFilePath = cstToStr(cst);
							//fName = to_string(get_timestamp());

							// 创建线程对象，指定要运行的函数和参数
							thread workerInfo(infoTask);
							// 获取线程句柄
							HANDLE hThread = workerInfo.native_handle();
							// 设置线程优先级
							SetThreadPriority(hThread, THREAD_PRIORITY_ABOVE_NORMAL);
							// 等待worker线程结束
							//workerInfo.join();
							//后台运行
							workerInfo.detach();
							// 当需要结束线程时，调用AfxEndThread
							//AfxEndThread(0);

						}
					}
					
				}
				// 忽略太频繁的点击
				return 0;

				//std::cout << "Worker thread is running..." << std::endl;
				// 执行一些任务 长时间运行的任务
				//std::cout << "Worker thread is working" << std::endl;
		
				//std::this_thread::sleep_for(std::chrono::seconds(1)); // 暂停一秒
				//std::cout << "Worker thread finished." << std::endl;
				// 工作完成，设置标志并通知条件变量
				//{
				//	std::lock_guard<std::mutex> lk(cv_m);
				//	done = true;
				//}
				//cv.notify_one();
			

			}
			break;
		case IDC_MESH_BUTTON:
			// 处理按钮点击事件
			//DisplayResourceNAMessageBox();
			//打开文件 对话框，选择文件并显示文件的路径
			{
				DWORD currentTime = GetTickCount64();

				if (infoTaskState) {
					CString strInfo;
					//strInfo.Format(_T("整数：%04d，浮点数：%08.2f，字符串：%s"), 10, 3.14, _T("TEST"));
					char c[300];
					strcpy_s(c, fName.c_str());
					strInfo.Format(_T("%s"), CStringW(c));
					MessageBox(
						NULL,
						"信息任务正在进行中...，\n 可到文件夹 outfile" + strInfo + " 检查输出的信息文件。",
						L"信息提示",
						MB_ICONASTERISK | MB_OK
					);
					return 0;
				}

				// 检查是否超过了防抖时间间隔
				if (currentTime - lastClickTime > DEBOUNCE_INTERVAL) {
					// 更新上次点击时间
					lastClickTime = currentTime;
					// 执行按钮点击的逻辑
					if (meshTaskState && iProgressBar != 100) {
						CString strInfo;
						//strInfo.Format(_T("整数：%04d，浮点数：%08.2f，字符串：%s"), 10, 3.14, _T("TEST"));
						char c[300];
						strcpy_s(c, fName.c_str());
						strInfo.Format(_T("%s"), CStringW(c));
						MessageBox(
							NULL,
							"切片任务正在进行中...，\n 可到文件夹 outfile" + strInfo + " 检查输出的切片文件。",
							L"信息提示",
							MB_ICONASTERISK | MB_OK
						);
						return 0;
					}
					else {
						
						
						CString cst = getEditText(hEdit);
						if (!(cst.IsEmpty())) {
							binFilePath = cstToStr(cst);
							//fName = to_string(get_timestamp());
							// 创建线程对象，指定要运行的函数和参数
							thread workerMesh(meshTask);
							// 获取线程句柄
							HANDLE hThread = workerMesh.native_handle();
							// 设置线程优先级
							SetThreadPriority(hThread, THREAD_PRIORITY_ABOVE_NORMAL);
							// 等待worker线程结束
							//workerMesh.join();
							// 后台运行
							workerMesh.detach();

							// 当需要结束线程时，调用AfxEndThread
							//AfxEndThread(0);
						}

					}
					
				}
				// 忽略太频繁的点击
				return 0;

				
				//std::cout << "Worker thread is running..." << std::endl;
				// 执行一些任务 长时间运行的任务
				//std::cout << "Worker thread is working" << std::endl;
				
				// 工作完成，设置标志并通知条件变量
				//{
				//	std::lock_guard<std::mutex> lk(cv_m);
				//	done = true;
				//}
				//cv.notify_one();
				//std::this_thread::sleep_for(std::chrono::seconds(1)); // 暂停一秒
				//std::cout << "Worker thread finished." << std::endl;


			}
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
		}

	}
	break;
	case WM_PAINT:
	{
		PAINTSTRUCT ps;
		HDC hdc = BeginPaint(hWnd, &ps);//设备环境句柄

		// 定义要绘制的文本
		CString text = "主要功能：对HiSim模拟器的模拟结果bin文件，油藏三维模型数据进行切片，输出交换格式ply，欢迎使用！";

		// 定义文本的绘制区域
		RECT rect = { 100, 100, 1000, 1000 };
		// 定义文本位置
		CRect rectText = { 10, 175, 1000, 1000 }; // x=100, y=300 是文本的起始位置
		// left top right bottom

		// TODO: 在此处添加使用 hdc 的任何绘图代码...

		 // 假设 hBitmap 已经加载了图片
		HDC hdcMem = CreateCompatibleDC(hdc);
		HBITMAP hOldBitmap = (HBITMAP)SelectObject(hdcMem, hBitmap);

		// 绘制图片到窗口的客户区
		BitBlt(hdc, 0, 0,  // 目标 DC 的位置
			GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), // 图片的大小
			hdcMem, 0, 0, // 源 DC 的位置
			SRCCOPY); // 光栅操作码

		// 恢复旧位图
		SelectObject(hdcMem, hOldBitmap);
		DeleteDC(hdcMem);

		// TCHAR greeting[] = _T("欢迎使用亿级油藏网格三维模型切片应用");
		// Here your application is laid out.
		// TextOut(hdc, 15, 15, greeting, _tcslen(greeting));
		// End application-specific layout section.

		// 创建字体结构并设置字体大小
		LOGFONT lf;
		memset(&lf, 0, sizeof(LOGFONT)); // 清零结构体
		lf.lfHeight = -MulDiv(11, GetDeviceCaps(hdc, LOGPIXELSY), 72); // 设置字体高度为12点
		_tcscpy_s(lf.lfFaceName, _T("Arial")); // 设置字体名称

		// 创建字体
		HFONT hFont = CreateFontIndirect(&lf);
		// 保存旧字体句柄
		HFONT hOldFont = (HFONT)SelectObject(hdc, hFont);

		GetClientRect(hWnd, &rect);
		DrawText(
			hdc,
			text,
			-1,
			&rectText,
			DT_SINGLELINE | DT_LEFT | DT_TOP 
		);


		// 恢复旧字体
		SelectObject(hdc, hOldFont);
		// 删除创建的字体
		DeleteObject(hFont);

		EndPaint(hWnd, &ps);


	}
	    break;
	case WM_SHOWWINDOW:
	{
		// 创建按钮的样式和位置
		hButton1 = CreateWindow(
			L"BUTTON",  // 预定义的按钮控件类名
			L"选择文件", // 按钮显示的文本
			WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // 按钮样式
			10,         // 按钮左上角的 x 坐标
			20,         // 按钮左上角的 y 坐标
			100,        // 按钮的宽度
			30,         // 按钮的高度
			hWnd,       // 父窗口句柄
			(HMENU)IDC_BROWSE_BUTTON,   // 按钮的ID（这里使用1作为示例）
			GetModuleHandle(NULL), // 应用程序实例句柄
			NULL);      // 不使用CREATESTRUCT结构

		// 在创建编辑控件之前，先创建一个子窗口作为容器
		//HWND hPaddingWnd = CreateWindow(
		//	TEXT("STATIC"), // 使用STATIC窗口作为容器
		//	TEXT(""),       // 无文本
		//	WS_CHILD | WS_VISIBLE | WS_BORDER,
		//	120, 20, 250, 30, // x, y, width, height
		//	hWnd,            // 父窗口句柄
		//	(HMENU)NULL,     // 不使用菜单
		//	GetModuleHandle(NULL),
		//	NULL);

		// 然后在子窗口中创建编辑控件
		//int padding = 3;
		// 创建文本框
		hEdit = CreateWindow(
			_T("EDIT"),        // 预定义的窗口类名
			_T(""),            // 文本框初始文本
			WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT , // 文本框样式
			//padding, padding,  // x, y 坐标加上内边距
			//250 - 2 * padding, 30 - 2 * padding, // 宽度和高度减去两边的内边距
			//hPaddingWnd, // 子窗口作为父窗口
			120,                // 文本框左上角的 x 坐标
			20,                // 文本框左上角的 y 坐标
			250,               // 文本框的宽度
			30,                // 文本框的高度
			hWnd,     // 父窗口句柄
			(HMENU)IDC_EDIT1,  // 文本框的 ID，需要在对话框类中定义相应的 ID
			GetModuleHandle(NULL), // 应用程序实例句柄
			NULL               // 不使用窗口创建数据
		);


		// 创建按钮的样式和位置
		hButton2 = CreateWindow(
			L"BUTTON",  // 预定义的按钮控件类名
			L"模型信息", // 按钮显示的文本
			WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // 按钮样式
			10,         // 按钮左上角的 x 坐标
			60,         // 按钮左上角的 y 坐标
			100,        // 按钮的宽度
			30,         // 按钮的高度
			hWnd,       // 父窗口句柄
			(HMENU)IDC_INFO_BUTTON,   // 按钮的ID（这里使用1作为示例）
			GetModuleHandle(NULL), // 应用程序实例句柄
			NULL);      // 不使用CREATESTRUCT结构


		// 创建按钮的样式和位置
		hButton3 = CreateWindow(
			L"BUTTON",  // 预定义的按钮控件类名
			L"输出模型", // 按钮显示的文本
			WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // 按钮样式
			10,         // 按钮左上角的 x 坐标
			100,         // 按钮左上角的 y 坐标
			100,        // 按钮的宽度
			30,         // 按钮的高度
			hWnd,       // 父窗口句柄
			(HMENU)IDC_MESH_BUTTON,   // 按钮的ID（这里使用1作为示例）
			GetModuleHandle(NULL), // 应用程序实例句柄
			NULL);      // 不使用CREATESTRUCT结构

		// 创建按钮的样式和位置
		/*hButton4 = CreateWindow(
			L"BUTTON",  // 预定义的按钮控件类名
			L"任务进度", // 按钮显示的文本
			WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // 按钮样式
			10,         // 按钮左上角的 x 坐标
			140,         // 按钮左上角的 y 坐标
			100,        // 按钮的宽度
			30,         // 按钮的高度
			hWnd,       // 父窗口句柄
			(HMENU)IDC_MESH_BUTTON,   // 按钮的ID（这里使用1作为示例）
			GetModuleHandle(NULL), // 应用程序实例句柄
			NULL);      // 不使用CREATESTRUCT结构
		*/
		hButton4 = CreateWindowEx(
			0,                     // 扩展样式
			L"EDIT",               // 控件类名
			L"任务进度",     // 初始文本
			WS_CHILD | WS_VISIBLE | WS_BORDER | ES_READONLY | ES_CENTER,  // 样式
			10,                    // x 坐标
			140,                    // y 坐标
			100,                   // 宽度
			30,                    // 高度
			hWnd,                  // 父窗口句柄
			(HMENU)IDC_MESH_BUTTON,              // 控件ID
			GetModuleHandle(NULL), // 应用程序实例句柄
			NULL);

		// 创建列表框
		hListBox = CreateWindow(
			L"LISTBOX",       // 预定义的列表框类名
			L"",              // 窗口标题（对于列表框通常为空）
			WS_VISIBLE | WS_CHILD | WS_BORDER | LBS_NOTIFY | WS_VSCROLL | LBS_HASSTRINGS,
			120,              // x 位置
			60,              // y 位置
			250,             // 宽度
			85,             // 高度
			hWnd,            // 父窗口句柄
			(HMENU)IDC_LISTBOX1,        // 列表框ID
			hInst,       // 实例句柄
			NULL             // 创建参数
		);

		// 创建进度条控件
		hProgressBar = CreateWindowEx(
			0,                  // 扩展样式
			PROGRESS_CLASS,     // 进度条类名
			NULL,               // 窗口名称
			WS_VISIBLE | WS_CHILD | WS_BORDER | LBS_NOTIFY, // 窗口样式
			120, 145,             // x, y 坐标
			251, 25,            // 宽度, 高度
			hWnd,               // 父窗口句柄
			(HMENU)IDC_PROGRESS1,           // 控件ID
			GetModuleHandle(NULL), // 实例句柄
			NULL);              // 创建参数

	}
	   break;
	case WM_LBUTTONDOWN:
	{
		//int xPos = LOWORD(lParam);
		//int yPos = HIWORD(lParam);
		//wchar_t buf[1024];
		//wsprintf(buf, TEXT("x = %d, y = %d"),xPos, yPos);
		//MessageBox(hWnd, buf, TEXT("按鼠标左键"), MB_OK);
		break;
	}
	case WM_KEYDOWN:
		//MessageBox(hWnd, TEXT("键盘"), TEXT("按键盘"), MB_OK);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
		break;
	}
	return 0;
}

// “关于”框的消息处理程序。
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	UNREFERENCED_PARAMETER(lParam);
	switch (message)
	{
	case WM_INITDIALOG:
		return (INT_PTR)TRUE;

	case WM_COMMAND:
		if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
		{
			EndDialog(hDlg, LOWORD(wParam));
			return (INT_PTR)TRUE;
		}
		break;
	}
	return (INT_PTR)FALSE;
}

// “选择文件”框的消息处理程序。
INT_PTR CALLBACK SelctFile(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	UNREFERENCED_PARAMETER(lParam);
	switch (message)
	{
	case WM_INITDIALOG:
		return (INT_PTR)TRUE;

	case WM_COMMAND:
		if (LOWORD(wParam) == IDC_BROWSE_BUTTON)
		{
			//打开文件 对话框，选择文件并显示文件的路径
			OnOpenBinFile(hDlg);
			return (INT_PTR)TRUE;
		}
		else if (LOWORD(wParam) == IDCANCEL) {
			EndDialog(hDlg, LOWORD(wParam));
			return (INT_PTR)TRUE;
		}
		break;
	}
	return (INT_PTR)FALSE;
}
